<!DOCTYPE html>
<html lang="zh-CN">
    <head>
  <!-- 元数据 -->
  <meta charset="utf-8">
  
  
  <title>事件循环 | 月蝉の小窝</title>
  
  <meta name="author" content="月蝉" />
  <meta http-equiv="Cache-Control" content="no-transform" />
  <meta http-equiv="Cache-Control" content="no-siteapp" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  <meta name="robots" content="index,follow" />
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
  <meta name="format-detection" content="telphone=no, email=no" />
  
    <meta name="keywords" content="Chrome, 原理" />
  
  <meta name="description" content="浏览器的进程模型何为进程？  程序运行需要有它自己专属的内存空间，可以把这块内存空间简单的理解为进程    每个应用至少有一个进程，进程之间相互独立，即使要通信，也需要双方同意 何为线程？  有了进程后，就可以运行程序的代码了  一个进程至少有一个线程，所以在进程开启后会自动创建一个线程来运行代码，该线程称之为主线程  如果程序需要同时执行多块代码，主线程就会启动更多的线程来执行代码，所以一个进程">
<meta property="og:type" content="article">
<meta property="og:title" content="事件循环">
<meta property="og:url" content="https://moon-cicada.gitee.io/blog/2023/10/29/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86/%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF/index.html">
<meta property="og:site_name" content="月蝉の小窝">
<meta property="og:description" content="浏览器的进程模型何为进程？  程序运行需要有它自己专属的内存空间，可以把这块内存空间简单的理解为进程    每个应用至少有一个进程，进程之间相互独立，即使要通信，也需要双方同意 何为线程？  有了进程后，就可以运行程序的代码了  一个进程至少有一个线程，所以在进程开启后会自动创建一个线程来运行代码，该线程称之为主线程  如果程序需要同时执行多块代码，主线程就会启动更多的线程来执行代码，所以一个进程">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://moon-cicada.gitee.io/blog/images/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86/images/1.png">
<meta property="og:image" content="https://moon-cicada.gitee.io/blog/images/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86/images/2.png">
<meta property="og:image" content="https://moon-cicada.gitee.io/blog/images/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86/images/3.png">
<meta property="og:image" content="https://moon-cicada.gitee.io/blog/images/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86/images/4.png">
<meta property="og:image" content="https://moon-cicada.gitee.io/blog/images/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86/images/5.png">
<meta property="og:image" content="https://moon-cicada.gitee.io/blog/images/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86/images/6.png">
<meta property="article:published_time" content="2023-10-29T12:20:30.000Z">
<meta property="article:modified_time" content="2023-10-29T04:45:39.953Z">
<meta property="article:author" content="月蝉">
<meta property="article:tag" content="原理">
<meta property="article:tag" content="Chrome">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://moon-cicada.gitee.io/blog/images/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86/images/1.png">
  
  <!-- 站点验证相关 -->
  
    
    
    
  
  <!-- 样式表文件 -->
  <link rel="stylesheet" id="kratos-css" href="/blog/css/kratosr.min.css" media="all"></script>
  
    <link rel="stylesheet" id="darkmode-css" href="/blog/css/kr-color-dark.min.css" media="(prefers-color-scheme: dark)"></script>
    <script src="/blog/js/kr-dark.min.js"></script>
  
  
    <link rel="stylesheet" id="highlight-css" href="/blog/css/highlight/night-eighties.min.css" media="all"></script>
  
  <link rel="stylesheet" id="fontawe-css" href="/blog/vendors/font-awesome@4.7.0/css/font-awesome.min.css" media="all"></script>
  <link rel="stylesheet" id="nprogress-css" href="/blog/vendors/nprogress@0.2.0/nprogress.css" media="all"></script>
  
  
    <link rel="stylesheet" href="/blog/vendors/aplayer@1.10.1/dist/APlayer.min.css"></script>
  
  
    <link rel="stylesheet" href="/blog/vendors/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.css"></script>
  
  <!-- 不得不预先加载的一些JS文件 -->
  <script src="/blog/vendors/jquery@3.6.0/dist/jquery.min.js"></script>
  
    <script src="/blog/vendors/qrcode_js@1.0.0/qrcode.min.js"></script>
  
  
  <style>
    
    
  </style>
  
<meta name="generator" content="Hexo 6.3.0"></head>


    <body class="custom-background">
        <div id="kratos-wrapper">
    <div id="kratos-page">
        <div id="kratos-header">
            <header id="kratos-desktop-topnav" class="kratos-topnav">
                <div class="container">
                    <div class="nav-header">
                        <nav id="kratos-menu-wrap">
                            <ul id="kratos-primary-menu" class="sf-menu">
                                
                                    
                                    
                                        
                                            <li><a href="/blog/"><i class="fa fa-home"></i>首页</a></li>
                                        
                                    
                                        
                                            <li><a href="/blog/archives/"><i class="fa fa-file"></i>档案馆</a></li>
                                        
                                    
                                        
                                            <li><a href="/blog/about/"><i class="fa fa-paper-plane"></i>关于我</a></li>
                                        
                                    
                                
                            </ul>
                        </nav>
                    </div>
                </div>
            </header>
            <header id="kratos-mobile-topnav" class="kratos-topnav">
                <div class="container">
                    <div class="color-logo"><a href="/blog/">月蝉の小窝</a></div>
                    <div class="nav-toggle">
                        <a class="kratos-nav-toggle js-kratos-nav-toggle">
                            <i></i>
                        </a>
                    </div>
                </div>
            </header>
        </div>
        <div class="kratos-start kratos-hero-2">
            <!-- <div class="kratos-overlay"></div> -->
            <div class="kratos-cover kratos-cover-2 text-center">
                <div class="desc desc2 animate-box">
                    <a href="/blog/">
                        <h2>月蝉の小窝</h2> <br />
                        <span></span>
                    </a>
                </div>
            </div>
        </div>

        <div id="kratos-blog-post">
            <div class="container">
                <div id="main" class="row">
                    

        

            <section class="col-md-8">

        

            <article itemscope itemtype="https://schema.org/Article">
    
    <link itemprop="mainEntityOfPage" href="https://moon-cicada.gitee.io/blog/2023/10/29/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86/%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF/">
    <div class="kratos-hentry kratos-post-inner clearfix">
        <header class="kratos-entry-header">
            
                <h1 class="kratos-entry-title text-center" itemprop="name headline">事件循环</h1>
            
            
            <ul class="kratos-post-meta text-center">
                <li><time datetime="2023-10-29T12:20:30.000Z" itemprop="datePublished"><i class="fa fa-calendar"></i> 2023-10-29</time></li>
                <li itemprop="author" itemscope itemtype="https://schema.org/Person">
                    <i class="fa fa-user"></i> 作者 <span itemprop="name">月蝉</span>
                </li>
                
                    <li>
                        <i class="fa fa-edit"></i> 
                        
                        
                            ~3.97K
                        
                        字
                    </li>
                
                
                    <li id="/blog/2023/10/29/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86/%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF/" class="leancloud_visitors" data-flag-title="事件循环">
                        <i class="fa fa-eye"></i>
                        <span class="leancloud-visitors-count"> </span> 次阅读
                    </li>
                
            </ul>
        </header>
        <div class="kratos-post-content">
            
            <div id="expire-alert" class="alert alert-warning hidden" role="alert">
                <div class="icon"><i class="fa fa-warning"></i></div>
                <div class="text"><p>本文最后编辑于 <time datetime="1698554739953"></time> 前，其中的内容可能需要更新。</p></div>
            </div>
            
            
            
                <div class="kratos-post-inner-toc toc-div-class" >
                    <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B5%8F%E8%A7%88%E5%99%A8%E7%9A%84%E8%BF%9B%E7%A8%8B%E6%A8%A1%E5%9E%8B"><span class="toc-number">1.</span> <span class="toc-text">浏览器的进程模型</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BD%95%E4%B8%BA%E8%BF%9B%E7%A8%8B%EF%BC%9F"><span class="toc-number">1.1.</span> <span class="toc-text">何为进程？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BD%95%E4%B8%BA%E7%BA%BF%E7%A8%8B%EF%BC%9F"><span class="toc-number">1.2.</span> <span class="toc-text">何为线程？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%B5%8F%E8%A7%88%E5%99%A8%E6%9C%89%E5%93%AA%E4%BA%9B%E8%BF%9B%E7%A8%8B%E5%92%8C%E7%BA%BF%E7%A8%8B%EF%BC%9F"><span class="toc-number">1.3.</span> <span class="toc-text">浏览器有哪些进程和线程？</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B8%B2%E6%9F%93%E4%B8%BB%E7%BA%BF%E7%A8%8B%E6%98%AF%E5%A6%82%E4%BD%95%E5%B7%A5%E4%BD%9C%E7%9A%84%EF%BC%9F"><span class="toc-number">2.</span> <span class="toc-text">渲染主线程是如何工作的？</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BD%95%E4%B8%BA%E5%BC%82%E6%AD%A5%EF%BC%9F"><span class="toc-number">3.</span> <span class="toc-text">何为异步？</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#JS%E4%B8%BA%E4%BD%95%E4%BC%9A%E9%98%BB%E7%A2%8D%E6%B8%B2%E6%9F%93%EF%BC%9F"><span class="toc-number">4.</span> <span class="toc-text">JS为何会阻碍渲染？</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BB%BB%E5%8A%A1%E6%9C%89%E4%BC%98%E5%85%88%E7%BA%A7%E5%90%97%EF%BC%9F"><span class="toc-number">5.</span> <span class="toc-text">任务有优先级吗？</span></a></li></ol>
                </div>
            
            <hr />
            <div itemprop="articleBody"><h2 id="浏览器的进程模型"><a href="#浏览器的进程模型" class="headerlink" title="浏览器的进程模型"></a>浏览器的进程模型</h2><h3 id="何为进程？"><a href="#何为进程？" class="headerlink" title="何为进程？"></a>何为进程？</h3><p>  程序运行需要有它自己专属的内存空间，可以把这块内存空间简单的理解为进程<br /><br>  <img src="/blog/images/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86/images/1.png" alt="Alt text"><br /><br>  每个应用至少有一个进程，进程之间相互独立，即使要通信，也需要双方同意</p>
<h3 id="何为线程？"><a href="#何为线程？" class="headerlink" title="何为线程？"></a>何为线程？</h3><p>  有了进程后，就可以运行程序的代码了<br /><br>  一个进程至少有一个线程，所以在进程开启后会自动创建一个线程来运行代码，该线程称之为主线程<br /><br>  如果程序需要同时执行多块代码，主线程就会启动更多的线程来执行代码，所以一个进程中可以包含多个线程<br /><br>  <img src="/blog/images/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86/images/2.png" alt="Alt text"><br /></p>
<h3 id="浏览器有哪些进程和线程？"><a href="#浏览器有哪些进程和线程？" class="headerlink" title="浏览器有哪些进程和线程？"></a>浏览器有哪些进程和线程？</h3><p>  浏览器是一个多进程多线程的应用程序<br /><br>  为了避免相互印象，为了减少连环崩溃的几率，当启动浏览器后，它会自动启动多个线程。<br /><br>  <img src="/blog/images/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86/images/3.png" alt="Alt text"> <br /></p>
<blockquote>
<p>可以在浏览器的任务管理器中查看当前的所有进程 <br /><br>  其中，最主要的进程有：</p>
</blockquote>
<ol>
<li>浏览器进程 <br /><br>主要负责界面显示、用户交互、子进程管理等。浏览器进程内部会启动多个线程处理不同的任务。</li>
<li>网络进程 <br /><br>负责加载网络资源。网络进程内部会启动多个线程来处理不同的网络任务。</li>
<li>渲染进程 <br /><br>渲染进程启动后，会开启一个渲染主线程，主线程负责执行HTML、CSS、JS代码。 <br /><br>默认情况下，浏览器会为每个标签页开启一个新的渲染进程，以保证不同的标签页之间不相互影响。</li>
</ol>
<h2 id="渲染主线程是如何工作的？"><a href="#渲染主线程是如何工作的？" class="headerlink" title="渲染主线程是如何工作的？"></a>渲染主线程是如何工作的？</h2><p>渲染主线程是浏览器中最繁忙的线程，需要它处理的任务包括但不限于：</p>
<ul>
<li>解析HTML</li>
<li>解析CSS</li>
<li>计算样式</li>
<li>布局</li>
<li>处理图层</li>
<li>每秒把页面画60次</li>
<li>执行全局JS代码</li>
<li>执行事件处理函数</li>
<li>执行计时器的回调函数</li>
<li>……</li>
</ul>
<p>要处理这么多的任务，主线程遇到一个前所未有的难题：如何调度任务？ <br /><br>比如： <br /></p>
<ul>
<li>我正在执行一个JS函数，执行到一半的时候用户点击了按钮，我该立即去执行点击事件的处理函数吗？ <br /></li>
<li>我正在执行一个JS函数，执行到一半的时候某个计时器到达了时间，我该立即去执行它的回调吗？ <br /></li>
<li>浏览器进程通知我“用户点击了按钮”，与此同时，某个计时器也到达了时间，我应该处理哪一个呢？ <br /></li>
<li>…… <br /></li>
</ul>
<p>渲染主线程想出了一个绝妙的注意来处理这个问题：排队 <br /><br><img src="/blog/images/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86/images/4.png" alt="Alt text"> <br /></p>
<ol>
<li>在最开始的时候，渲染主线程会进入一个无限循环  <br /></li>
<li>每一次循环会检查消息队列中是否有任务存在。如果有，就取出第一个任务执行，执行完一个后进入下一次循环；如果没有，则进入休眠状态。 <br /></li>
<li>其他所有线程(包括其他进程的线程)可以随时向消息队列添加任务。新任务会加到消息队列的末尾。在添加新任务时，如果主线程是休眠状态，则会将其唤醒以继续循环拿取任务 <br /><br>这样一来，就可以让每个任务有条不紊的、持续的进行下去了。 <br /><br>整个过程，被称之为事件循环(event_loop)又叫消息循环(message_loop) <br /></li>
</ol>
<blockquote>
<p>为什么渲染进程不适用多个线程来处理这些事情？ <br /><br>浏览器渲染进程通常是单线程的，这是因为多线程处理可能会引发很多问题。以下是一些可能的问题： <br /></p>
<ol>
<li><p>竞态条件: 多线程处理会导致访问共享内存的竞争条件，可能导致数据不一致和死锁等问题。</p>
</li>
<li><p>同步问题：多线程需要进行同步，避免数据竞争和死锁，这会增加代码的复杂度和开销。</p>
</li>
<li><p>安全问题：多线程可能会存在安全漏洞，如数据泄露、内存溢出等问题。</p>
</li>
<li><p>性能问题：多线程处理可能会导致过多的上下文切换和内存消耗，从而降低程序的性能和稳定性。</p>
</li>
</ol>
<p>相比之下，单线程处理有以下优点：<br /></p>
<ol>
<li><p>简单易用：单线程的处理方式更加简单易用，开发人员不需要考虑多线程处理中的竞态条件、同步问题和安全问题。</p>
</li>
<li><p>可靠稳定：单线程处理避免了多线程处理中的死锁和资源争用等问题，从而提高了程序的可靠性和稳定性。</p>
</li>
<li><p>高效节省：单线程处理可以避免多线程处理中的上下文切换和内存消耗等问题，从而提高了程序的性能和节省了系统资源。</p>
</li>
</ol>
<p>虽然单线程处理可能会存在一些缺点，如无法充分利用多核CPU等问题，但是它是目前浏览器渲染进程的常用处理方式，可以通过事件循环和异步编程等技术来提高程序的性能和并发处理能力。</p>
</blockquote>
<h2 id="何为异步？"><a href="#何为异步？" class="headerlink" title="何为异步？"></a>何为异步？</h2><p>代码在执行过程中，会遇到一些无法立即处理的任务，比如： <br /></p>
<ul>
<li>计时完成后需要执行的任务 – setTimeout、setInterval <br /></li>
<li>网络通信完成后需要执行的任务 – XHR、Fetch <br /></li>
<li>用户操作后需要执行的任务 – addEventListener <br /><br>如果让渲染主线程等待这些任务的时机达到，就会导致主线程长期处于[阻塞]的状态，从而导致浏览器[卡死] <br /><br><img src="/blog/images/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86/images/5.png" alt="Alt text"> <br /><br>渲染主线程承担着极其重要的工作，无论如何都不能阻塞！ <br /><br>因此，浏览器选择异步来解决这个问题 <br /><br><img src="/blog/images/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86/images/6.png" alt="Alt text"> <br /><br>使用异步的方式，渲染主线程永不阻塞<blockquote>
<p>面试题：如何理解JS的异步？</p>
<p>参考答案：<br>  JS是一门单线程的语言，这是因为它运行在浏览器的渲染主线程中，而渲染主线程只有一个。<br /><br>  渲染主线程承担着诸多的工作，渲染页面、执行JS都在其中运行。<br>  如果使用同步的方式，就极有可能导致主线程产生阻塞，从而导致消息队列中的很多任务无法得到执行。这样一来，一方面会导致繁忙的主线程白白的消耗时间，另一方面导致页面无法及时更新，给用户造成卡死现象。 <br /><br>  所以浏览器采用异步的方式来避免。具体做法是当某些任务发生时，比如计时器、网络、事件监听，主线程将任务交给其他线程去处理，自身立即结束任务的执行，转而执行后续代码。当其他线程完成时，将事先传递的回调函数包装成任务，加入到消息队列的末尾排队，等待主线程调度执行。 <br /><br>  在这种异步模式下，浏览器永不阻塞，从而最大限度的保证了单线程的流畅运行。</p>
</blockquote>
</li>
</ul>
<h2 id="JS为何会阻碍渲染？"><a href="#JS为何会阻碍渲染？" class="headerlink" title="JS为何会阻碍渲染？"></a>JS为何会阻碍渲染？</h2><p>先看代码 <br /></p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">h1</span>&gt;</span>Hello Word!<span class="tag">&lt;/<span class="name">h1</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">button</span>&gt;</span>change<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="language-javascript"></span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">var</span> h1 = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&#x27;h1&#x27;</span>);</span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">var</span> btn = <span class="variable language_">document</span>.<span class="title function_">querySelector</span>(<span class="string">&#x27;button&#x27;</span>);</span></span><br><span class="line"><span class="language-javascript">  </span></span><br><span class="line"><span class="language-javascript">  <span class="comment">// 死循环指定的时间</span></span></span><br><span class="line"><span class="language-javascript">  <span class="keyword">function</span> <span class="title function_">delay</span>(<span class="params">duration</span>) &#123;</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">var</span> start = <span class="title class_">Date</span>.<span class="title function_">now</span>();</span></span><br><span class="line"><span class="language-javascript">    <span class="keyword">while</span>(<span class="title class_">Date</span>.<span class="title function_">now</span>() - start &lt; duration)&#123;&#125;</span></span><br><span class="line"><span class="language-javascript">  &#125;</span></span><br><span class="line"><span class="language-javascript">  </span></span><br><span class="line"><span class="language-javascript">  btn.<span class="property">onclick</span> = <span class="keyword">function</span>(<span class="params"></span>) &#123;</span></span><br><span class="line"><span class="language-javascript">    h1.<span class="property">tetContent</span> = <span class="string">&#x27;世界你好！&#x27;</span></span></span><br><span class="line"><span class="language-javascript">    <span class="title function_">delay</span>(<span class="number">3000</span>);</span></span><br><span class="line"><span class="language-javascript">  &#125;</span></span><br><span class="line"><span class="language-javascript"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>在渲染主线程执行全局JS时，获取h1、btn，定义一个函数delay，给btn绑定了一个点击事件，此时渲染主线程执行全局JS完毕，然后交互线程会监听btn点击，点击后执行事件函数，当用户点击了btn后，会将事件函数放到消息队列中，此时渲染主线程会从消息队列中拿到此事件函数，然后执行，执行的过程中，首先改变h1元素的文本，然后产生一个渲染任务函数放到消息队列中，事件函数继续执行，此时事件函数调用了delay函数，delay函数死循环3秒钟，当delay函数循环结束后，事件函数也执行完毕，此时再从消息队列中拿到渲染任务函数，执行渲染任务函数重新绘制页面 <br /></p>
<blockquote>
<p>JS会阻碍渲染是因为JS和渲染都在渲染主线程中执行</p>
</blockquote>
<h2 id="任务有优先级吗？"><a href="#任务有优先级吗？" class="headerlink" title="任务有优先级吗？"></a>任务有优先级吗？</h2><p>任务没有优先级，在消息队列中先进先出</p>
<p>但消息队列是有优先级的</p>
<p>根据W3C的最新解释：</p>
<ul>
<li><p>每各任务都有一个任务类型，同一个类型的任务必须在一个队列，不同类型的任务可以分属于不同的队列。在一次事件循环中，浏览器可以根据实际情况从不同的队列中取出任务执行。</p>
</li>
<li><p>浏览器必须准备好一个微队列，微队列中的任务优先所有其他任务执行。</p>
<p><a target="_blank" rel="noopener" href="https://html.spec.whatwg.org/multipage/webappapis.html#perform-a-microtask-checkpoint">微任务官方文档</a></p>
</li>
</ul>
<blockquote>
<p>随着浏览器的复杂度急剧提升，W3C不再使用宏队列的说法</p>
</blockquote>
<p>在目前chrome的实现中，至少包含了下面的队列：</p>
<ul>
<li>延时队列：用于存放计时器到达后的回调任务，优先级[中]</li>
<li>交互队列：用于存放用户操作后产生的事件处理任务，优先级[高]</li>
<li>微队列：用户存放需要最快执行的任务，优先级[最高]</li>
</ul>
<blockquote>
<p>添加任务到微队列的主要方式是使用Promise、MutationObserver</p>
<p>例如：</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 立即把一个函数添加到微队列</span></span><br><span class="line"></span><br><span class="line"><span class="title class_">Promise</span>.<span class="title function_">resolve</span>().<span class="title function_">then</span>(函数)</span><br></pre></td></tr></table></figure>
</blockquote>
<blockquote>
<p>浏览器还有很多其他的队列，由于和我们开发关系不大，不作考虑</p>
</blockquote>
<blockquote>
<p>面试题：阐述一下JS的事件循环</p>
<p>参考答案：</p>
<p>事件循环又叫消息循环，是浏览器渲染主线程的工作方式。<br /><br>在Chrome的源码中，它开启一个不会结束的for循环，每次循环从消息队列中取出第一个任务执行，而其他线程只需要在合适的时候将任务加入到队列末尾即可。<br /><br>过去把消息队列简单分为宏队列和微队列，这种说法目前已经无法满足复杂的浏览器环境，取而代之的是一种更加灵活多变的处理方式。<br /><br>根据W3C官方的解释，每个任务有不同的类型，同类型的任务必须在同一个队列，不同的任务可以属于不同的队列。不同任务队列有不同的优先级，在一次事件循环中，由浏览器自行决定取哪一个队列的任务。但浏览器必须由一个微队列，微队列的任务一定具有最高的优先级，必须优先调度执行。</p>
</blockquote>
<blockquote>
<p>面试题：JS中的计时器能做到精确计时吗？为什么？</p>
<p>参考答案：</p>
<p>不行，因为：</p>
<ol>
<li>计算机硬件没有原子钟，无法做到精确计时</li>
<li>操作系统的计时函数本身就有少量偏差，由于JS的计时器最终调用的是操作系统的函数，也就携带了这些偏差</li>
<li>按照W3C的标准，浏览器实现计时器时，如果嵌套层级超过5层，则会带有4毫秒的最少时间，这样在计时时间少于4毫秒时又带来了偏差</li>
<li>受事件循环的影响，计时器的回调函数只能在主线程空闲时运行，因此又带来了偏差</li>
</ol>
</blockquote>
</div>
        </div>
        
            <div class="kratos-copyright text-center clearfix">
                <h5 itemprop="copyrightNotice">本作品采用 <a rel="license nofollow" target="_blank" href="https://creativecommons.org/licenses/by-sa/4.0/">知识共享署名-相同方式共享 4.0 国际许可协议</a> 进行许可</h5>
            </div>
        
        <footer class="kratos-entry-footer clearfix">
            
                <div class="post-like-donate text-center clearfix" id="post-like-donate">
                
                
                    <a class="share" href="javascript:;"><i class="fa fa-share-alt"></i> 分享</a>
                    <div class="share-wrap" style="display: none;">
    <div class="share-group">
        <a href="javascript:;" class="share-plain qq" onclick="share('qq');" rel="nofollow">
            <div class="icon-wrap">
                <i class="fa fa-qq"></i>
            </div>
        </a>
        <a href="javascript:;" class="share-plain qzone" onclick="share('qzone');" rel="nofollow">
            <div class="icon-wrap">
                <i class="fa fa-star"></i>
            </div>
        </a>
        <a href="javascript:;" class="share-plain weixin pop style-plain" rel="nofollow">
            <div class="icon-wrap">
                <i class="fa fa-weixin"></i>
            </div>
            <div class="share-int">
                <div class="qrcode" id="wechat-qr"></div>
                <p>打开微信“扫一扫”，打开网页后点击屏幕右上角分享按钮</p>
            </div>
        </a>
        <a href="javascript:;" class="share-plain weibo" onclick="share('weibo');" rel="nofollow">
            <div class="icon-wrap">
                <i class="fa fa-weibo"></i>
            </div>
        </a>
        <a href="javascript:;" class="share-plain facebook style-plain" onclick="share('facebook');" rel="nofollow">
            <div class="icon-wrap">
                <i class="fa fa-facebook"></i>
            </div>
        </a>
        <a href="javascript:;" class="share-plain twitter style-plain" onclick="share('twitter');" rel="nofollow">
            <div class="icon-wrap">
                <i class="fa fa-twitter"></i>
            </div>
        </a>
    </div>
    <script type="text/javascript">
        $(()=>{
            new QRCode("wechat-qr", {
                text: "https://moon-cicada.gitee.io/blog/2023/10/29/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86/%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF/",
                width: 150,
                height: 150,
                correctLevel : QRCode.CorrectLevel.H
            });
        });
        function share(dest) {
            const qqBase        = "https://connect.qq.com/widget/shareqq/index.html?";
            const weiboBase     = "https://service.weibo.com/share/share.php?";
            const qzoneBase     = "https://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?";
            const facebookBase  = "https://www.facebook.com/sharer/sharer.php?";
            const twitterBase   = "https://twitter.com/intent/tweet?";
            const hostUrl       = "https://moon-cicada.gitee.io/blog/2023/10/29/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86/%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF/";
            const title         = "「事件循环」";
            const excerpt       = `浏览器的进程模型何为进程？  程序运行需要有它自己专属的内存空间，可以把这块内存空间简单的理解为进程    每个应用至少有一个进程，进程之间相互独立，即使要通信，也需要双方同意
何为线程？  有了进程后，就可以运行程序的代码了  一个...`;
            let _URL;
            switch (dest) {
                case "qq"       : _URL = qqBase+"url="+hostUrl+"&title="+title+"&desc=&summary="+excerpt+"&site=cxpy";     break;
                case "weibo"    : _URL = weiboBase+"url="+hostUrl+"&title="+title+excerpt;                                 break;
                case "qzone"    : _URL = qzoneBase+"url="+hostUrl+"&title="+title+"&desc=&summary="+excerpt+"&site=cxpy";  break;
                case "facebook" : _URL = facebookBase+"u="+hostUrl;                                                        break;
                case "twitter"  : _URL = twitterBase+"text="+title+excerpt+"&url="+hostUrl;                                break;
            }
            window.open(_URL);
        };
    </script>
</div>
                
                </div>
            
            <div class="footer-tag clearfix">
                <div class="pull-left">
                <i class="fa fa-tags"></i>
                    <a class="tag-none-link" href="/blog/tags/Chrome/" rel="tag">Chrome</a>, <a class="tag-none-link" href="/blog/tags/%E5%8E%9F%E7%90%86/" rel="tag">原理</a>
                </div>
                <div class="pull-date">
                    <time datetime="2023-10-29T04:45:39.953Z" itemprop="dateModified">最后编辑：2023-10-29</time>
                </div>
            </div>
        </footer>
    </div>
    
        <nav class="navigation post-navigation clearfix" role="navigation">
            
            <div class="nav-previous clearfix">
                <a title=" Hello World" href="/blog/2023/10/28/hello-world/">&lt; 上一篇</a>
            </div>
            
            
            <div class="nav-next clearfix">
                <a title=" 浏览器渲染原理" href="/blog/2023/10/29/浏览器原理/浏览器渲染原理/">下一篇 &gt;</a>
            </div>
            
        </nav>
    
    
        <div id="v-comments" class="post-comments"></div>
<script>
    var load_comm = () => {
        const init = () => {
            new Valine({
                el: '#v-comments',
                appId: 'cM5eOxMg63PZfmD94zakD07F-gzGzoHsz',
                appKey: 'Ig7h0RQDY2duLi5iYpxbM1ZW',
                visitor: true,
                enableQQ: true,
                path: '/blog/2023/10/29/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86/%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF/'
            });
        }
        if (typeof Valine === 'undefined') {
            const src = '/blog/vendors/valine@1.4.18/dist/Valine.min.js';
            $.getScript(src, init);
        } else {
            init();
        }
    };
</script>
<noscript>Please enable JavaScript to view the <a target="_blank" rel="noopener" href="https://valine.js.org/">comments powered by Valine.</a></noscript>

    
</article>

        

            </section>

        

                
            

<section id="kratos-widget-area" class="col-md-4 hidden-xs hidden-sm">
    <!-- 文章和页面根据splitter来分割，没有的话就从头开始设置为sticky -->
    
    
                <aside id="krw-about" class="widget widget-kratos-about clearfix">
    <div class="photo-background"></div>
    <div class="photo-wrapper clearfix">
        <div class="photo-wrapper-tip text-center">
            <img class="about-photo" src="/blog/images/avaths.webp" loading="lazy" decoding="auto" />
        </div>
    </div>
    <div class="textwidget">
        <p class="text-center"></p>
    </div>
    <div class="site-meta">
        <a class="meta-item" href="/blog/archives/">
            <span class="title">
                文章
            </span>
            <span class="count">
                6
            </span>
        </a>
        <a class="meta-item" href="/blog/categories/">
            <span class="title">
                分类
            </span>
            <span class="count">
                4
            </span>
        </a>
        <a class="meta-item" href="/blog/tags/">
            <span class="title">
                标签
            </span>
            <span class="count">
                6
            </span>
        </a>
    </div>
</aside>
            
                    <div class="sticky-area">
                
                    <aside id="krw-toc" class="widget widget-kratos-toc clearfix toc-div-class" >
    <div class="photo-background"></div>
    <h4 class="widget-title no-after">
        <i class="fa fa-compass"></i>
        文章目录
        <span class="toc-progress-bar" role="progressbar" aria-label="阅读进度："></span>
    </h4>
    <div class="textwidget">
        <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B5%8F%E8%A7%88%E5%99%A8%E7%9A%84%E8%BF%9B%E7%A8%8B%E6%A8%A1%E5%9E%8B"><span class="toc-text">浏览器的进程模型</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BD%95%E4%B8%BA%E8%BF%9B%E7%A8%8B%EF%BC%9F"><span class="toc-text">何为进程？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BD%95%E4%B8%BA%E7%BA%BF%E7%A8%8B%EF%BC%9F"><span class="toc-text">何为线程？</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E6%B5%8F%E8%A7%88%E5%99%A8%E6%9C%89%E5%93%AA%E4%BA%9B%E8%BF%9B%E7%A8%8B%E5%92%8C%E7%BA%BF%E7%A8%8B%EF%BC%9F"><span class="toc-text">浏览器有哪些进程和线程？</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E6%B8%B2%E6%9F%93%E4%B8%BB%E7%BA%BF%E7%A8%8B%E6%98%AF%E5%A6%82%E4%BD%95%E5%B7%A5%E4%BD%9C%E7%9A%84%EF%BC%9F"><span class="toc-text">渲染主线程是如何工作的？</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BD%95%E4%B8%BA%E5%BC%82%E6%AD%A5%EF%BC%9F"><span class="toc-text">何为异步？</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#JS%E4%B8%BA%E4%BD%95%E4%BC%9A%E9%98%BB%E7%A2%8D%E6%B8%B2%E6%9F%93%EF%BC%9F"><span class="toc-text">JS为何会阻碍渲染？</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%BB%BB%E5%8A%A1%E6%9C%89%E4%BC%98%E5%85%88%E7%BA%A7%E5%90%97%EF%BC%9F"><span class="toc-text">任务有优先级吗？</span></a></li></ol>
    </div>
</aside>
                
                
  <aside id="krw-categories" class="widget widget-kratos-categories clearfix">
    <h4 class="widget-title"><i class="fa fa-folder"></i>分类目录</h4>
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/blog/categories/HTTP/">HTTP</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/blog/categories/Hello/">Hello</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/blog/categories/html/">html</a><span class="category-list-count">2</span></li><li class="category-list-item"><a class="category-list-link" href="/blog/categories/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86/">浏览器原理</a><span class="category-list-count">2</span></li></ul>
  </aside>


            
                
  <aside id="krw-tags" class="widget widget-kratos-tags clearfix">
    <h4 class="widget-title"><i class="fa fa-tags"></i>标签聚合</h4>
      <div class="tag-clouds">
        <a href="/blog/tags/Chrome/" style="font-size: 0.7em;">Chrome</a> <a href="/blog/tags/HTTP/" style="font-size: 0.6em;">HTTP</a> <a href="/blog/tags/%E5%89%8D%E7%AB%AF/" style="font-size: 0.7em;">前端</a> <a href="/blog/tags/%E5%8D%8F%E8%AE%AE/" style="font-size: 0.6em;">协议</a> <a href="/blog/tags/%E5%8E%9F%E7%90%86/" style="font-size: 0.7em;">原理</a> <a href="/blog/tags/%E5%9F%BA%E7%A1%80/" style="font-size: 0.8em;">基础</a>
      </div>
  </aside>

            
                
  <aside id="krw-posts" class="widget widget-kratos-posts">
  <h4 class="widget-title"><i class="fa fa-file"></i>最新文章</h4>
  <div class="tab-content">
      <ul class="list-group">
        
        
          
          
            <a class="list-group-item" href="/blog/2023/11/03/HTTP/HTTP%E5%9F%BA%E7%A1%80/"><i class="fa  fa-book"></i> HTTP基础</a>
            
          
        
          
          
            <a class="list-group-item" href="/blog/2023/10/31/HTML/%E6%96%87%E6%A1%A3%E7%B1%BB%E5%9E%8B%E5%A3%B0%E6%98%8E%E6%A0%87%E7%AD%BE/"><i class="fa  fa-book"></i> 文档类型声明标签</a>
            
          
        
          
          
            <a class="list-group-item" href="/blog/2023/10/31/HTML/html%E5%9F%BA%E7%A1%80/"><i class="fa  fa-book"></i> html基础</a>
            
          
        
          
          
            <a class="list-group-item" href="/blog/2023/10/29/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86/%E6%B5%8F%E8%A7%88%E5%99%A8%E6%B8%B2%E6%9F%93%E5%8E%9F%E7%90%86/"><i class="fa  fa-book"></i> 浏览器渲染原理</a>
            
          
        
          
          
            <a class="list-group-item" href="/blog/2023/10/29/%E6%B5%8F%E8%A7%88%E5%99%A8%E5%8E%9F%E7%90%86/%E4%BA%8B%E4%BB%B6%E5%BE%AA%E7%8E%AF/"><i class="fa  fa-book"></i> 事件循环</a>
            
          
        
          
            
      </ul>
  </div>
  </aside>

            
    </div>
</section>
        
        </div>
    </div>
</div>
<footer>
    <div id="footer"  class="ap-lrc"  >
        <div class="container">
            <div class="row">
                <div class="col-md-6 col-md-offset-3 footer-list text-center">
                    <ul class="kratos-social-icons">
                        <!-- Keep for compatibility -->
                        
                        
                        
                        
                        
                        
                        
                        
                        
                        <!-- New links -->
                        
                    </ul>
                    <ul class="kratos-copyright">
                        <div>
                            <li>&copy; 2023 月蝉の小窝 版权所有.</li>
                            <li>本站已运行<span id="span_dt">Loading...</span></li>
                        </div>
                        <div>
                            <li>Theme <a href="https://github.com/Candinya/Kratos-Rebirth" target="_blank">Kratos:Rebirth</a></li>
                            <li>Site built with&nbsp;<i class="fa fa-heart throb" style="color:#d43f57"></i>&nbsp;by 月蝉.</li>
                        </div>
                        <div>
                            <li>Powered by <a href="https://hexo.io" target="_blank" rel="nofollow">Hexo</a></li>
                            <li>Hosted on <a href="https://github.io" target="_blank">Github Pages</a></li>
                        </div>
                        <div>
                            
                            
                        </div>
                    </ul>
                </div>
            </div>
        </div>
        <div class="kr-tool text-center">
            <div class="tool">
                
                    <div class="box search-box">
                        <a href="/blog/search/">
                            <span class="fa fa-search"></span>
                        </a>
                    </div>
                
                
                    <div class="box theme-box" id="darkmode-switch">
                        <span class="fa fa-adjust"></span>
                    </div>
                
                
                    <div class="box theme-box" id="snow-switch">
                        <span class="fa fa-snowflake-o"></span>
                    </div>
                
                
            </div>
            <div class="box gotop-box">
                <span class="fa fa-chevron-up"></span>
            </div>
        </div>
    </div>
</footer>
</div>
</div>

        <script defer src="/blog/vendors/bootstrap@3.3.4/dist/js/bootstrap.min.js"></script>
<script defer src="/blog/vendors/nprogress@0.2.0/nprogress.js"></script>
<script>
    if (!window.kr) {
        window.kr = {};
    }
    window.kr.notMobile = (!(navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i)));
    window.kr.siteRoot = "/blog/";
</script>

    <div>
        <canvas id="snow"></canvas>
        <script async src="/blog/js/snow.min.js"></script>
    </div>


    <script async src="/blog/js/candy.min.js"></script>



    <script defer src="/blog/vendors/aplayer@1.10.1/dist/APlayer.min.js"></script>
    
    <script defer src="/blog/vendors/meting@2.0.1/dist/Meting.min.js"></script>
    <meting-js
        server="netease"
        type="playlist"
        id="3204190542"
        order="random"
        fixed="true"
    >
    </meting-js>



    <script defer src="/blog/vendors/@fancyapps/fancybox@3.5.7/dist/jquery.fancybox.min.js"></script>

<script defer src="/blog/js/kratosr.min.js"></script>
<script defer src="/blog/js/pjax.min.js"></script>



<!-- Extra support for third-party plguins  -->


    </body>
</html>